package com.chaoxing.ai.speech.service.Impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baidu.aip.speech.AipSpeech;
import com.baidu.aip.speech.TtsResponse;
import com.baidu.aip.util.Util;
import com.chaoxing.ai.speech.service.SpeechService;
import com.chaoxing.ai.speech.utils.SoundConvert;
import com.google.common.collect.Maps;
import it.sauronsoftware.jave.AudioInfo;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncoderException;
import it.sauronsoftware.jave.MultimediaInfo;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
public class SpeechServiceImpl implements SpeechService {
    //设置APPID/AK/SK
    public static final String APP_ID = "26505677";
    public static final String API_KEY = "uq3ZMRUx4orx35zf0wEAcEbA";
    public static final String SECRET_KEY = "rISlGw3bk8IgHFTPdjlAdP6duPQjpHhl";
    private static final AipSpeech SPEECH_CLIENT = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);

    /**
     * 根据云盘存储对象id解析语音文件内容
     * @param templatepath 上传的路径
     * @param fileName     文件名称
     * @return 解析结果
     */
    public String speechRecognition(String templatepath,String fileName,String suffixName) throws JSONException, EncoderException {
        // 初始化一个AipSpeech
        AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);

        // 可选：设置网络连接参数
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);

        // 可选：设置代理服务器地址, http和socket二选一，或者均不设置
//        client.setHttpProxy("proxy_host", proxy_port);  // 设置http代理
//        client.setSocketProxy("proxy_host", proxy_port);  // 设置socket代理

        // 可选：设置log4j日志输出格式，若不设置，则使用默认配置
        // 也可以直接通过jvm启动参数设置此环境变量
        //System.setProperty("aip.log4j.conf", "path/to/your/log4j.properties");

        // 调用接口
        String filePath=templatepath+"\\"+fileName;         //文件的路径
        System.out.println(filePath);

        JSONObject res = client.asr(filePath, suffixName, 16000, null);
        System.out.println(res.toString(2));
        return res.toString(2);
    }

    public String speechRecognition8(String templatepath,String fileName,String suffixName) throws JSONException, EncoderException {
        // 初始化一个AipSpeech
        AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);

        // 可选：设置网络连接参数
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);

        // 可选：设置代理服务器地址, http和socket二选一，或者均不设置
//        client.setHttpProxy("proxy_host", proxy_port);  // 设置http代理
//        client.setSocketProxy("proxy_host", proxy_port);  // 设置socket代理

        // 可选：设置log4j日志输出格式，若不设置，则使用默认配置
        // 也可以直接通过jvm启动参数设置此环境变量
        //System.setProperty("aip.log4j.conf", "path/to/your/log4j.properties");

        // 调用接口
        String filePath=templatepath+"\\"+fileName;         //文件的路径
        System.out.println(filePath);
        //使用Jave获取音频的数据
        File source = new File(filePath);
        Encoder encoder = new Encoder();
        MultimediaInfo m = encoder.getInfo(source);
        long millisecond = m.getDuration();             //获取总时长
        System.out.println(millisecond);
        AudioInfo audio = m.getAudio();                 //音频文件
        int bitRate = audio.getBitRate();               //获得码流
        JSONObject res = client.asr(filePath, suffixName, 8000, null);
        System.out.println(res.toString(2));
        return res.toString(2);
    }
    /**
     * 语言合成
     * @throws JSONException
     */
    @Override
    public  String inSpeechRecognition (String words) throws JSONException {
        // 初始化一个AipSpeech
        AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
        // 可选：设置网络连接参数
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);

        // 可选：设置代理服务器地址, http和socket二选一，或者均不设置
        //client.setHttpProxy("proxy_host", proxy_port);  // 设置http代理
        // client.setSocketProxy("proxy_host", proxy_port);  // 设置socket代理

        // 可选：设置log4j日志输出格式，若不设置，则使用默认配置
        // 也可以直接通过jvm启动参数设置此环境变量
        //System.setProperty("aip.log4j.conf", "path/to/your/log4j.properties");

        // 调用接口
        TtsResponse res = client.synthesis(words, "zh", 1, null);
        byte[] data = res.getData();
        JSONObject res1 = res.getResult();
        if (data != null) {
            try {
                //输出目录
                Util.writeBytesToFileSystem(data, "E:\\api-speeh\\public\\demo.mp3");
                // 讲Mp3转换成统一的wav格式
                String mp3FilePath = "E:\\api-speeh\\public\\demo.mp3";
                String pcmFilepath = "E:\\api-speeh\\public\\demo.pcm";
                String wavFilepath = "E:\\api-speeh\\public\\demo.wav";
                SoundConvert.Mp3ToPcm(mp3FilePath,pcmFilepath);
                SoundConvert.pcmToWav16K(pcmFilepath,wavFilepath);
                File file1 = new File(mp3FilePath);
                File file2 = new File(pcmFilepath);
                //删除多余的文件保证内存率
                file1.delete();
                file2.delete();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "文件合成成功!";
        }
        if (res1 != null) {
            System.out.println(res1.toString(2));
        }
        return "文件合成失败!";
    }

    /**
     * 根据objectId解析语音文件内容
     */
    public Map<String, Object> handlerSpeechByObjectId2(String objectId, AipSpeech client) {
        List<String> allowTypes = Arrays.asList("mp3", "m4a", "pcm");
        // 音频mp3或m4a转换为wav命令：ffmpeg -i input.mp3 -acodec pcm_s16le -ac 2 -ar 44100 output.wav
        String audioParseMp3OrM4aToWavOrder = "ffmpeg -i %s -acodec pcm_s16le -ac 2 -ar 16000 %s";
        // 音频wav转pcm命令：ffmpeg -i input.wav -f s16le -ar 44100 -acodec pcm_s16le output.raw
        String audioParseWavToPcmOrder = "ffmpeg -i %s -f s16le -ar 44100 -acodec pcm_s16le %s";
        // 音频pcm转wav命令：ffmpeg -f s16le -ar 44100 -ac 2 -acodec pcm_s16le -i input.raw output.wav
        String audioParsePcmToWavOrder = "ffmpeg -f s16le -ar 44100 -ac 2 -acodec pcm_s16le -i %s %s";
        // 更改采样频率命令：ffmpeg -i sample_16k_nnorm.wav -ac 1 -ar 16000 -acodec pcm_s16le sample_16k_nnorm_16bit.wav
        String audioChangeSampleFrequencyOrder = "ffmpeg -i %s -ac 1 -ar 16000 -acodec pcm_s16le %s";
        // 临时缓存目录
        // String tempFilePath = "D:\\tempFiles\\%s";
        String tempFilePath = "/usr/local/tempFiles/%s";

        Map<String, Object> result = Maps.newHashMap();
        result.put("success", true);
        String errorMsg = "";
        if (!StringUtils.hasText(objectId)) {
            errorMsg = "objectId不能为空";
            result.put("success", false);
            result.put("errorMsg", errorMsg);
            return result;
        }
        String fileInfo = HttpUtil.get("http://cs.ananas.chaoxing.com/status/" + objectId);
        cn.hutool.json.JSONObject fileInfoObject = JSONUtil.parseObj(fileInfo);
        System.out.println("fileInfo:" + fileInfoObject);
        String downloadUrl = fileInfoObject.getStr("download");
        String mp3FileUrl = fileInfoObject.getStr("http");
        String fileName = fileInfoObject.getStr("filename");
        System.out.println("mp3FileUrl:" + mp3FileUrl);
        System.out.println("fileName:" + fileName);
        fileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".mp3";
        String sourceFilePath = String.format(tempFilePath, fileName);
        URL url = null;
        FileOutputStream os = null;
        try {
            url = new URL(mp3FileUrl);
            URLConnection urlConnection = url.openConnection();
            urlConnection.setRequestProperty("referer", "https://bgs.chaoxing.com/");
            urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36");
            InputStream inputStream = urlConnection.getInputStream();
            File file = new File(sourceFilePath);
            os = new FileOutputStream(file);
            int b = 0;
            byte[] buffer = new byte[1024];
            while (b != -1) {
                b = inputStream.read(buffer);
                if (b != -1) {
                    os.write(buffer, 0, b);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            result.put("success", false);
            result.put("errorMsg", errorMsg);
            return result;
        } finally {
            if (Objects.nonNull(os)) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        String fileNamePrefix = fileName.substring(0, fileName.lastIndexOf("."));
        String fileSuffix = !StringUtils.hasText(fileName) ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
        List<String> allowedFileTypes = Arrays.asList("m4a", "wav", "mp3", "pcm", "amr");
        if (allowedFileTypes.contains(fileSuffix)) {
            String targetWavFilePath = String.format(tempFilePath, fileNamePrefix + ".wav");
            String cmdParseCommand = String.format(audioParseMp3OrM4aToWavOrder, sourceFilePath, targetWavFilePath);
            executeCommand(cmdParseCommand);
            String finalFilePath = String.format(tempFilePath, fileNamePrefix + "_16bit.wav");
            String cmdChangeCommand = String.format(audioChangeSampleFrequencyOrder, targetWavFilePath, finalFilePath);
            executeCommand(cmdChangeCommand);
            org.json.JSONObject resultObject = client.asr(finalFilePath, "wav", 16000, null);
            System.out.println(resultObject.toString(2));
            result.put("result", resultObject.get("result"));
            deleteFileByPath(Arrays.asList(sourceFilePath, targetWavFilePath, finalFilePath));
        } else {
            errorMsg = "音频文件类型不允许：" + fileSuffix + "，允许的类型：m4a、wav、mp3、pcm";
            result.put("success", false);
            result.put("errorMsg", errorMsg);
            return result;
        }
        return result;
    }

    /**
     * 清除临时文件
     */
    public void deleteFileByPath(List<String> filePathList) {
        try {
            for (String filePath : filePathList) {
                File file = new File(filePath);
                if (file.exists() && file.isFile()) {
                    file.delete();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void executeCommand(String cmdCommand) {
        try {
            Process process = Runtime.getRuntime().exec(cmdCommand);
            InputStream is = process.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String content = br.readLine();
            while (content != null) {
                System.out.println(content);
                content = br.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
